/*
 * @Author: 我想吃余 483766615@qq.com
 * @Date: 2025-10-18 14:02:37
 * @LastEditors: 我想吃余 483766615@qq.com
 * @LastEditTime: 2025-10-19 16:47:08
 * @FilePath: /code/oscode/pipe use/proc_pool.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "task.hpp"
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
#include <unistd.h>
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>

#define N 2

const int processnum = 5;
std::vector<task_t> tasks;

//先描述
class channel
{
public:
    //construct
    channel(int cmdfd, pid_t workerid, std::string& processname)
    :_cmdfd(cmdfd)
    ,_workerid(workerid)
    ,_processname(processname)
    {}
public:
    int _cmdfd;               // 发送任务的文件描述符
    pid_t _workerid;          // 子进程的PID
    std::string _processname; // 子进程的名字 -- 方便我们打印日志
};

void worker()
{
    while(true)
    {
        int cmdcode = 0;
        int n = read(0, &cmdcode, sizeof(int));
        // 检查退出信号
        if(n == sizeof(int))
        {
            //成功读取任务码
            std::cout <<"worker say@ get a command: "<< getpid() << " : cmdcode: " <<  cmdcode << std::endl;
            //执行该任务
            if(cmdcode >= 0 && cmdcode < tasks.size())
                tasks[cmdcode]();
        }
        else break;
    }
}

// 不同参数类型的传参方式：
// 输入：const &
// 输出：*
// 输入输出：&
void InitProcPool(std::vector<channel>* channels)
{
    //存储父进程的所有写端fd
    std::vector<int> wfd;
    for(int i = 0; i < processnum; ++i)
    {
        //建立管道
        int pipefd[N] = {0};
        int n = pipe(pipefd);
        assert(!n);
        (void)n;

        //创建子进程
        pid_t id = fork();
        if(id == 0)
        {
            //child
            std::cout << "clean father history wfd:";
            for(auto e : wfd)
            {
                close(e);
                std::cout << " " << e;
            }
            std::cout << std::endl;
            
            close(pipefd[1]);//关闭写端
            dup2(pipefd[0], 0);
            worker();

            //退出
            std::cout << "process : " << getpid() << " quit" << std::endl;
            exit(0);
        }
        //father
        close(pipefd[0]);//关闭读端

        //初始化channel
        std::string procname = "process-" + std::to_string(i);
        channels->push_back(channel(pipefd[1], id, procname));
        //每创建一个写端就保存
        wfd.push_back(pipefd[1]);
        sleep(1);
    }
}

void CtrlWorker(const std::vector<channel>& channels)
{
    int cnt = 0;
    int which = 0;
    while(true)
    {
        //选择任务
        //随机选取任务
        int cmdcode = rand()%tasks.size();
        //分配任务

        //a. 随机数选取子进程
        //int which = rand()%channels.size();

        //b. 轮询
        which %= channels.size();

        std::cout << "father say: " << " cmdcode: " <<
            cmdcode << " already sendto " << channels[which]._workerid << " process name: " 
                << channels[which]._processname << std::endl;
        //发送任务
        write(channels[which]._cmdfd, &cmdcode, sizeof(int));

        cnt++;
        if(cnt >= 10) break;

        which++;
        sleep(1);
    }
}

void QuitProc(const std::vector<channel>& channels)
{
    for(auto &e : channels)
    {
        close(e._cmdfd);
        waitpid(e._workerid, nullptr, 0);
    }
}

int main()
{
    // 加载任务
    LoadTask(&tasks);

    srand(time(nullptr)^1024^getpid());//种下随机数种子
    // 再组织
    std::vector<channel> channels;
    //1. 初始化
    InitProcPool(&channels);
    //2. 控制子进程
    CtrlWorker(channels);
    //3. 清理
    QuitProc(channels);

    return 0;
}